/*
 * Copyright 2014 Alex Curran
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.github.amlcurran.showcaseview;

import android.content.Context;
import android.content.res.Resources;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Rect;
import android.text.DynamicLayout;
import android.text.Layout;
import android.text.SpannableString;
import android.text.TextPaint;
import android.text.TextUtils;
import android.text.style.TextAppearanceSpan;

import com.seleniti.enpareja.android.R;

/**
 * Draws the text as required by the ShowcaseView
 */
class TextDrawer {

	private static final float STROKE = 3;
	private final TextPaint titlePaint;
	private final TextPaint textPaint;
	private final Context context;
	private final ShowcaseAreaCalculator calculator;
	private final float padding;
	private final float actionBarOffset;

	private CharSequence mTitle, mDetails;
	private float[] mBestTextPosition = new float[3];
	private DynamicLayout mDynamicTitleLayout;
	private DynamicLayout mDynamicDetailLayout;
	private TextAppearanceSpan mTitleSpan;
	private TextAppearanceSpan mDetailSpan;
	private boolean hasRecalculated;
	private int offsetX;
	private int offsetY;
	private int theme;

	public TextDrawer(Resources resources, ShowcaseAreaCalculator calculator, Context context) {
		padding = resources.getDimension(R.dimen.text_padding);
		actionBarOffset = resources.getDimension(R.dimen.action_bar_offset);

		this.calculator = calculator;
		this.context = context;

		titlePaint = new TextPaint();
		titlePaint.setAntiAlias(true);

		textPaint = new TextPaint();
		textPaint.setAntiAlias(true);
	}

	public void draw(Canvas canvas) {
		if (shouldDrawText()) {
			float[] textPosition = getBestTextPosition();

			float dx = textPosition[0];
			float dy = textPosition[1];
			int width = (int) textPosition[2];

			if (!TextUtils.isEmpty(mTitle)) {
				if (hasRecalculated) {
					mDynamicTitleLayout = new DynamicLayout(mTitle, titlePaint, width, Layout.Alignment.ALIGN_NORMAL,
							1.0f, 1.0f, true);
				}
			}

			if (!TextUtils.isEmpty(mDetails)) {
				if (hasRecalculated) {
					mDynamicDetailLayout = new DynamicLayout(mDetails, textPaint, width, Layout.Alignment.ALIGN_NORMAL,
							1.2f, 1.0f, true);
				}
			}

			int totalWidth = Math.max((mDynamicTitleLayout != null ? mDynamicTitleLayout.getWidth() : 0),
					(mDynamicDetailLayout != null ? mDynamicDetailLayout.getWidth() : 0));
			int totalHeight = (mDynamicTitleLayout != null ? mDynamicTitleLayout.getHeight() : 0)
					+ (mDynamicDetailLayout != null ? mDynamicDetailLayout.getHeight() : 0);
			boolean drawn = (!TextUtils.isEmpty(mTitle) && (mDynamicTitleLayout != null))
					|| (!TextUtils.isEmpty(mDetails) && (mDynamicDetailLayout != null));

			if (drawn) {
				canvas.save();
				Paint paint = new Paint();
				paint.setStrokeWidth(STROKE);
				TypedArray styled = context.obtainStyledAttributes(theme, R.styleable.ShowcaseView);
				paint.setColor(styled.getColor(R.styleable.ShowcaseView_sv_showcaseColor, ShowcaseView.HOLO_BLUE));

				canvas.translate(dx - (STROKE*2), dy - (STROKE*2));

				canvas.drawRect(0.0f, 0.0f, totalWidth + (STROKE*4), totalHeight + (STROKE*4), paint);
				
				paint.setColor(Color.WHITE);
				paint.setStrokeWidth(0);

				canvas.drawRect(STROKE, STROKE, totalWidth + (STROKE*3), totalHeight + (STROKE*3), paint);

				canvas.restore();
				styled.recycle();
			}

			if (!TextUtils.isEmpty(mTitle)) {
				if (mDynamicTitleLayout != null) {
					canvas.save();
					canvas.translate(dx, dy);
					Paint paint = new Paint();
					paint.setStrokeWidth(0);
					paint.setColor(Color.WHITE);

					canvas.drawRect(0.0f, 0.0f, (float) mDynamicTitleLayout.getWidth(),
							(float) mDynamicTitleLayout.getHeight(), paint);
					mDynamicTitleLayout.draw(canvas);
					drawn = true;
					canvas.restore();
				}
			}

			if (!TextUtils.isEmpty(mDetails)) {
				if (hasRecalculated) {
					mDynamicDetailLayout = new DynamicLayout(mDetails, textPaint, width, Layout.Alignment.ALIGN_NORMAL,
							1.2f, 1.0f, true);
				}
				float offsetForTitle = mDynamicTitleLayout != null ? mDynamicTitleLayout.getHeight() : 0;
				if (mDynamicDetailLayout != null) {
					canvas.save();
					canvas.translate(dx, dy + offsetForTitle);
					Paint paint = new Paint();
					paint.setStrokeWidth(0);
					paint.setColor(Color.WHITE);

					canvas.drawRect(0.0f, 0.0f, (float) mDynamicDetailLayout.getWidth(),
							(float) mDynamicDetailLayout.getHeight(), paint);
					mDynamicDetailLayout.draw(canvas);
					drawn = true;
					canvas.restore();
				}
			}

		}
		hasRecalculated = false;
	}

	public void setContentText(CharSequence details) {
		if (details != null) {
			SpannableString ssbDetail = new SpannableString(details);
			ssbDetail.setSpan(mDetailSpan, 0, ssbDetail.length(), 0);
			mDetails = ssbDetail;
		}
	}

	public void setContentTitle(CharSequence title) {
		if (title != null) {
			SpannableString ssbTitle = new SpannableString(title);
			ssbTitle.setSpan(mTitleSpan, 0, ssbTitle.length(), 0);
			mTitle = ssbTitle;
		}
	}

	/**
	 * Calculates the best place to position text
	 * 
	 * @param canvasW
	 *            width of the screen
	 * @param canvasH
	 *            height of the screen
	 * @param shouldCentreText
	 */
	public void calculateTextPosition(int canvasW, int canvasH, ShowcaseView showcaseView, boolean shouldCentreText) {

		Rect showcase = showcaseView.hasShowcaseView() ? calculator.getShowcaseRect() : new Rect();

		int[] areas = new int[4]; // left, top, right, bottom
		areas[0] = (showcase.left * canvasH);
		areas[1] = (showcase.top * canvasW);
		areas[2] = (canvasW - showcase.right) * canvasH;
		areas[3] = (canvasH - showcase.bottom) * canvasW;

		int largest = 0;
		for (int i = 1; i < areas.length; i++) {
			if (areas[i] > areas[largest])
				largest = i;
		}

		// Position text in largest area
		switch (largest) {
		case 0:
			mBestTextPosition[0] = padding;
			mBestTextPosition[1] = padding;
			mBestTextPosition[2] = showcase.left - 2 * padding;
			break;
		case 1:
			mBestTextPosition[0] = padding;
			mBestTextPosition[1] = padding + actionBarOffset;
			mBestTextPosition[2] = canvasW - 2 * padding;
			break;
		case 2:
			mBestTextPosition[0] = showcase.right + padding;
			mBestTextPosition[1] = padding;
			mBestTextPosition[2] = (canvasW - showcase.right) - 2 * padding;
			break;
		case 3:
			mBestTextPosition[0] = padding;
			mBestTextPosition[1] = showcase.bottom + padding;
			mBestTextPosition[2] = canvasW - 2 * padding;
			break;
		}
		if (shouldCentreText) {
			// Center text vertically or horizontally
			switch (largest) {
			case 0:
			case 2:
				mBestTextPosition[1] += canvasH / 4;
				break;
			case 1:
			case 3:
				mBestTextPosition[2] /= 2;
				mBestTextPosition[0] += canvasW / 4;
				break;
			}
		} else {
			// As text is not centered add actionbar padding if the text is left
			// or right
			switch (largest) {
			case 0:
			case 2:
				mBestTextPosition[1] += actionBarOffset;
				break;
			}
		}
		
		mBestTextPosition[0]+=this.offsetX;
		mBestTextPosition[1]+=this.offsetY;

		hasRecalculated = true;
	}

	public void setTitleStyling(int styleId) {
		mTitleSpan = new TextAppearanceSpan(this.context, styleId);
		setContentTitle(mTitle);
	}

	public void setDetailStyling(int styleId) {
		mDetailSpan = new TextAppearanceSpan(this.context, styleId);
		setContentText(mDetails);
	}

	public CharSequence getContentTitle() {
		return mTitle;
	}

	public CharSequence getContentText() {
		return mDetails;
	}

	public float[] getBestTextPosition() {
		return mBestTextPosition;
	}

	public boolean shouldDrawText() {
		return !TextUtils.isEmpty(mTitle) || !TextUtils.isEmpty(mDetails);
	}

	public int getOffsetX() {
		return offsetX;
	}

	public void setOffsetX(int offsetX) {
		this.offsetX = offsetX;
	}

	public int getOffsetY() {
		return offsetY;
	}

	public void setOffsetY(int offsetY) {
		this.offsetY = offsetY;
	}

	public void setStyle(int theme) {
		this.theme = theme;
	}
}
